package com.sinosoft.dsp.component.bpm.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.jbpm.api.Configuration;
import org.jbpm.xsdobject.Process;
import org.primefaces.json.JSONException;
import org.primefaces.json.JSONObject;
import org.primefaces.model.chart.flow.FlowChartModel;
import org.primefaces.model.chart.flow.FlowDefaultAttributes;
import org.primefaces.model.chart.flow.FlowElementSet;
import org.primefaces.model.chart.flow.FlowHop;
import org.primefaces.model.chart.flow.FlowStep;
import org.primefaces.model.chart.flow.hop.SysArrowType;
import org.primefaces.model.chart.flow.step.PictureStep;
import org.primefaces.model.chart.flow.util.FlowGraphHelper;

import com.sinosoft.dsp.component.bpm.exception.SinoBPMException;
import com.sinosoft.dsp.component.bpm.facade.engine.ProcessResourceFacade;
import com.sinosoft.dsp.platform.utils.SinoManagedBean;
import com.sinosoft.dsp.system.core.log.Log;
import com.sinosoft.dsp.system.utils.Const;
import com.sinosoft.dsp.system.utils.ReflectionUtils;

/**
 * 流程对象、流程定义与xml相互解析
 * 
 * @author 潘巍（PeterPan）
 * @since 2011-8-15 下午02:42:10
 * 
 */
public class ProcessParse {

	private static final Log log = Log.getLog(ProcessParse.class.getName());

	// 流程对象的包名
	public final static String PROCESS_PACKAGE_NAME = "org.jbpm.xsdobject";

	// 流程schema的文件名
	public final static String PROCESS_SCHEMA_FILE = "/jpdl-4.3.xsd";

	// 对象转换成xml文件的临时文件路径
	public final static String processXmlPath = "";

	JAXBContext jaxbContext;

	Schema schema;

	private static ProcessParse instance;

	public static ProcessParse getInstance() {
		if (instance == null) {
			try {
				instance = new ProcessParse();
				instance.jaxbContext = JAXBContext
						.newInstance(PROCESS_PACKAGE_NAME);
				SchemaFactory schemaFactory = SchemaFactory
						.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
				instance.schema = schemaFactory.newSchema(new StreamSource(
						instance.getResourceStream(PROCESS_SCHEMA_FILE)));
			} catch (Exception ex) {
				log.error("初始化流程解析出现错误");
			}
		}
		return instance;
	}

	private InputStream getResourceStream(String path) {
		InputStream sourceStream = Configuration.class
				.getResourceAsStream(path);
		if (sourceStream == null) {
			log.error("获得输入流出现错误");
		}
		return sourceStream;
	}

	/**
	 * 流程对象转换为流程的xml文件
	 * 
	 * @param jaxbElement
	 *            流程的java对象
	 * @return file 流程的xml文件
	 */
	public static String objectToXmlOfProcess(Object jaxbElement) {

		String rtn = "";
		try {
			if (jaxbElement instanceof Process) {
				OutputStream is = new ByteArrayOutputStream(4096);

				Marshaller marshaller = getInstance().jaxbContext
						.createMarshaller();
				marshaller.setSchema(getInstance().schema);
				marshaller.marshal(jaxbElement, is);
				rtn = is.toString();
				is.close();
			}

		} catch (Exception ex) {
			log.error("流程对象转换为流程的xml文件出现错误");
		}
		return rtn;

	}

	/**
	 * 流程的xml文件转换成流程java对象
	 * 
	 * @param file
	 *            流程的文件
	 * @return Process 流程的java对象
	 */
	public static Process xmlToObjectOfProcess(InputStream is) {
		Process process = null;
		try {
			Unmarshaller unmarshaller = getInstance().jaxbContext
					.createUnmarshaller();
			unmarshaller.setSchema(getInstance().schema);
			process = (Process) unmarshaller.unmarshal(is);

		} catch (Exception ex) {
			log.error("流程的xml文件转换成流程java对象出现错误");
		}
		return process;

	}

	/**
	 * 将流程对象转换成页面显示的JSON对象
	 * 
	 * @param process
	 *            流程对象
	 * @return JSONObject 流程的页面用的JSON对象
	 */
	public static JSONObject objectToJsonOfProcess(Process process) {
		if (process != null) {
			JSONObject jo = new JSONObject();
			// 创建图形对象

			// 创建线条对象
			return jo;
		}
		return null;
	}

	/**
	 * 获得活动
	 * 
	 * @param process
	 * @param name
	 * @return
	 */
	public static Object getActivity(Process process, String name) {
		if (process != null) {
			List<Object> actives = process.getDescriptionAndSwimlaneAndOn();
			if (actives != null) {
				for (int i = 0; i < actives.size(); i++) {
					Object obj = actives.get(i);
					if (name.equals(ActivityType.getActivityName(obj))) {
						return obj;
					}
				}
			}
		}
		return null;
	}

	public static FlowChartModel processToCanvasObject(Process process,
			String exParams) throws SinoBPMException {
		try {
			FlowChartModel model = FlowGraphHelper.createFlowChartModel();
			FlowElementSet els = model.getElementSet();
			FlowDefaultAttributes defaultAttributes = model
					.getDefaultAttributes();
			FlowHop onInitHop = FlowGraphHelper.createHop();
			onInitHop.addAttribute(FlowHop.ARROW_END_TYPE, SysArrowType.DEFAULT
					.getName());
			onInitHop.addAttribute(FlowHop.TEXT_STYLE, "green");
			onInitHop.addAttribute(FlowHop.ON_CONTEXT_MENU,
					"SinoComponent.Bpm.Define.hopContextMenu(canvasObj,flowObj,this,"
							+ exParams + ")");
			onInitHop.addAttribute(FlowHop.ON_DBLCLICK,
					"SinoComponent.Bpm.Define.hopDblClick(canvasObj,flowObj,this,"
							+ exParams + ")");
			onInitHop.addAttribute(FlowHop.ON_MOVE,
					"SinoComponent.Bpm.Define.hopMove(canvasObj,flowObj,this,"
							+ exParams + ")");

			FlowStep onInitStep = new FlowStep() {

				@Override
				public String getType() {
					return "";
				}

				@Override
				public JSONObject toJSON() {
					try {
						// 添加父类属性
						JSONObject jo = super.toJSON();
						jo.put(PictureStep.S_WIDTH, 48);
						jo.put(PictureStep.S_HEIGHT, 48);
						return jo;
					} catch (JSONException e) {
						log.error("创建初始化步骤节点出现错误。");
					}
					return null;
				}
			};
			onInitStep.addAttribute(FlowStep.ON_CONTEXT_MENU,
					"SinoComponent.Bpm.Define.stepContextMenu(canvasObj,flowObj,this,"
							+ exParams + ")");
			onInitStep.addAttribute(FlowStep.ON_DBLCLICK,
					"SinoComponent.Bpm.Define.stepDblClick(canvasObj,flowObj,this,"
							+ exParams + ")");
			onInitStep.addAttribute(FlowStep.ON_MOVE,
					"SinoComponent.Bpm.Define.stepMove(canvasObj,flowObj,this,"
							+ exParams + ")");
			onInitStep
					.addAttribute(
							FlowStep.ON_END_HOP,
							"SinoComponent.Bpm.Define.stepEndHop(this.config.canvasEls,this.config.stateHop.fromElId,el.el.id,this.config.stateHop)");
			onInitStep
					.addAttribute(FlowStep.ON_ACCEPT_HOP,
							"SinoComponent.Bpm.Define.stepAcceptHop(this.config.stateHop,el.el)");
			defaultAttributes.setOnInitStep(onInitStep);
			defaultAttributes.setOnInitHop(onInitHop);
			model.setDefaultAttributes(defaultAttributes);

			if (process != null) {
				List<Object> actives = process.getDescriptionAndSwimlaneAndOn();
				if (actives != null) {
					// 创建节点
					Map<String, Integer> activityIdAndName = new HashMap<String, Integer>();
					for (int i = 0; i < actives.size(); i++) {
						Object obj = actives.get(i);
						ActivityType at = ActivityType.getActivityType(obj
								.getClass());
						if (at != null) {
							FlowStep step = at.createCanvasStep(obj);
							step.setId(String.valueOf(i));
							els.addStep(step);

							activityIdAndName.put((String) ReflectionUtils
									.invokeMethod(obj, "getName"), i);
						}
					}

					// 创建连线
					for (int i = 0; i < actives.size(); i++) {
						Object obj = actives.get(i);
						ActivityType at = ActivityType.getActivityType(obj
								.getClass());
						at.createCanvasHops(els, obj, i, activityIdAndName);
					}
				}
			}

			return model;

		} catch (SinoBPMException e) {
			throw e;
		} catch (Exception e) {
			throw new SinoBPMException("创建流程解析发生错误");
		}
	}

	/**
	 * 解析目录的资源文件
	 * 
	 * @param str
	 * @return
	 * @throws JSONException
	 */
	public static JSONObject parseDir(String deploymentId, String resourceName) {
		try {
			ProcessResourceFacade psf = SinoManagedBean
					.findBean("processResourceFacade");
			String re = psf.getDeploymentResource(deploymentId, resourceName);
			if (Const.isEmpty(re)) {
				re = "{}";
			}
			return new JSONObject(re);
		} catch (Exception e) {
			log.error("解析目录的资源文件出现错误。");
		}
		return null;
	}

	/**
	 * 解析Jpdl资源文件
	 * 
	 * @param deploymentId
	 * @param resourceName
	 * @return
	 */
	public static Process parseJpdlDefine(String deploymentId,
			String resourceName) {
		InputStream inputStream = null;
		try {
			JbpmConfig jbpmConfig = SinoManagedBean.findBean("jbpmConfig");

			inputStream = jbpmConfig.getRepositoryService()
					.getResourceAsStream(deploymentId, resourceName);
			return ProcessParse.xmlToObjectOfProcess(inputStream);

		} catch (Exception e) {
			log.error("解析Jpdl资源文件出现错误。");
		} finally {
			try {
				if (inputStream != null)
					inputStream.close();
			} catch (IOException e) {
				log.debug("无法关闭流");
			}
		}
		return null;
	}
}
